﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Threading.Tasks;
using System.Linq;
using System.Reflection;

using alib;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;

namespace agree.schema
{
	using xaml;

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class schema_prop_attachable : schema_prop
	{
		public schema_prop_attachable(Schema sch, PropertyInfo pi_direct, Type Ti_direct)
			: base(sch, pi_direct)
		{
			this.Ti_direct = Ti_direct;
			this.TargetType = sch.find_type(typeof(ISchemaObj));
		}

		public schema_type TargetType { get; private set; }

		public readonly Type Ti_direct;
		public bool Inherits;

		public Object external_property_key;

		public bool IsSetOnItem(Object obj)
		{
			Debug.Assert(obj is ISchemaObj);
			return GetValue(obj) != null;
		}

		xaml_attached _xa;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public xaml_attached XamlAttachedProperty
		{
			get
			{
				if (_xa == null)
					_xa = new xaml_attached(this);
				return _xa;
			}
		}

		bool is_unsanctioned_impl(ISchemaObj item, String s_meth)
		{
			MethodInfo mi;
			if ((mi = item.GetType().GetMethod(s_meth)) == null)
				throw new Exception();

			return !Ti_direct.IsAssignableFrom(mi.DeclaringType);
		}

		public override Object GetValue(Object obj, BindingFlags bf, Binder binder, Object[] index, CultureInfo culture)
		{
			ISchemaObj item = obj as ISchemaObj;
			if (item == null)
				return null;
			if (Ti_direct != null &&
				Ti_direct.IsAssignableFrom(item.GetType()) &&
				!is_unsanctioned_impl(item, "get_" + Name))
			{
				return base.GetValue(obj, bf, binder, index, culture);
			}
			return VirtualPropertyStore.vps.GetPropertyValue(item, this);
		}

		public override void SetValue(Object obj, Object value, BindingFlags bf, Binder binder, Object[] index, CultureInfo culture)
		{
			ISchemaObj item = (ISchemaObj)obj;

			if (Ti_direct != null &&
				Ti_direct.IsAssignableFrom(item.GetType()) &&
				!is_unsanctioned_impl(item, "set_" + Name))
			{
				base.SetValue(obj, value, bf, binder, index, culture);
			}
			else
			{
				VirtualPropertyStore.vps.SetPropertyValue(item, this, value);

				base.do_propchange(obj, value);
			}
		}
	};
}
